{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "1d573782",
   "metadata": {},
   "source": [
    "# 2.12 Periodic Spaces\n",
    "\n",
    "To define spaces with periodic constraints, we have to create meshes where the nodes on one side are identified with nodes on the opposite side."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8a74944d",
   "metadata": {},
   "outputs": [],
   "source": [
    "from ngsolve import *\n",
    "from ngsolve.webgui import Draw\n",
    "from netgen.occ import *"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cb091337",
   "metadata": {},
   "outputs": [],
   "source": [
    "shape = Rectangle(1,1).Face()\n",
    "\n",
    "shape.edges.Max(X).name = \"right\"\n",
    "shape.edges.Min(X).name = \"left\"\n",
    "shape.edges.Max(Y).name = \"top\"\n",
    "shape.edges.Min(Y).name = \"bot\"\n",
    "\n",
    "shape.edges.Max(Y).Identify(shape.edges.Min(Y), \"bt\")\n",
    "shape.edges.Max(X).Identify(shape.edges.Min(X), \"lr\")\n",
    "\n",
    "mesh = Mesh(OCCGeometry(shape, dim=2).GenerateMesh(maxh=0.1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e155efc8",
   "metadata": {},
   "outputs": [],
   "source": [
    "plist = []\n",
    "for pair in mesh.ngmesh.GetIdentifications():\n",
    "    plist += list(mesh.vertices[pair[0]-1].point) + [0]\n",
    "    plist += list(mesh.vertices[pair[1]-1].point) + [0]\n",
    "Draw(mesh, objects=[{\"type\" : \"lines\", \"position\" : plist, \"name\": \"identification\", \"color\": \"purple\"}]);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9c7bbc0d",
   "metadata": {},
   "outputs": [],
   "source": [
    "fes = Periodic(H1(mesh,order=3))\n",
    "u,v = fes.TnT()\n",
    "a = BilinearForm(grad(u)*grad(v)*dx+u*v*dx).Assemble()\n",
    "f = LinearForm(exp(-100*( (x-0.8)**2+(y-0.8)**2))*v*dx).Assemble()\n",
    "                 \n",
    "gfu = GridFunction(fes,\"u\")\n",
    "gfu.vec.data = a.mat.Inverse(fes.FreeDofs()) * f.vec\n",
    "\n",
    "Draw (gfu);"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b5c87c35",
   "metadata": {},
   "source": [
    "## A piece of cake"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bfa10a1b",
   "metadata": {},
   "outputs": [],
   "source": [
    "f = WorkPlane(Axes((0,0,0), Y,X)).MoveTo(0.3,0).Rectangle(3,1).Face()\n",
    "ax = Axis ((0,0,0), Z)\n",
    "cake = f.Revolve(ax, 30)\n",
    "cake.faces.Min(Y).name=\"f1\"\n",
    "cake.faces.Max(Y-0.5*X).name=\"f2\"\n",
    "cake.faces.Min(Z).name=\"bot\"\n",
    "\n",
    "cake.faces[\"f1\"][0].Identify(cake.faces[\"f2\"][0], \"id\",\n",
    "                            trafo=Rotation(ax, 30))\n",
    "Draw (cake);"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ee7caf6b",
   "metadata": {},
   "source": [
    "NGSolve does not support elements having dofs on the primary and secondary side. To avoid them we refine the mesh once:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6c13e41e",
   "metadata": {},
   "outputs": [],
   "source": [
    "mesh = Mesh(OCCGeometry(cake).GenerateMesh(maxh=0.5)) # .Curve(3)\n",
    "mesh.ngmesh.Refine()\n",
    "\n",
    "plist = []\n",
    "for pair in mesh.ngmesh.GetIdentifications():\n",
    "    plist += list(mesh.vertices[pair[0]-1].point)\n",
    "    plist += list(mesh.vertices[pair[1]-1].point)\n",
    "Draw(mesh, objects=[{\"type\" : \"lines\", \"position\" : plist, \"name\": \"identification\", \"color\": \"purple\"}]);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "827d6d67",
   "metadata": {},
   "outputs": [],
   "source": [
    "fes = Periodic(H1(mesh, order=2, dirichlet=\"bot\"))\n",
    "\n",
    "u,v = fes.TnT()\n",
    "\n",
    "a = BilinearForm(grad(u)*grad(v)*dx).Assemble()\n",
    "f = LinearForm(100*exp(-9*( (x-2.5)**2+y**2+(z-0.5)**2))*v*dx).Assemble()\n",
    "                 \n",
    "gfu = GridFunction(fes,\"u\")\n",
    "gfu.vec.data = a.mat.Inverse(fes.FreeDofs()) * f.vec\n",
    "\n",
    "Draw (gfu);"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0d21ce69",
   "metadata": {},
   "source": [
    "## Application: computing band diagrams\n",
    "\n",
    "[Computing band diagrams](dispersion.ipynb)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4047b67e",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
